/*
当前middleware弃用，原因是：grpc原生已实现这些功能

grpc已实现以下Chain方法，可以像洋葱模型式进行调用拦截器。但是链式的调用会包裹到

grpc.WithUnaryInterceptor()
grpc.WithStreamInterceptor()
grpc.UnaryInterceptor()
grpc.StreamInterceptor()
内进行执行，如果是使用了以上方法注册的option，则以上这些方法是在最外层执行

以下方法可以完成中间件的功能
grpc.ChainStreamInterceptor()
grpc.ChainUnaryInterceptor()
grpc.WithChainStreamInterceptor()
grpc.WithChainUnaryInterceptor()

可以参考demos中的fgrpcopts_test,利用fgin.RegisterGrpcServerOptions,fgin.RegisterGrpcDialOptions实现自定义grpc的中间件注册

*/

package middleware

import (
	"context"

	"google.golang.org/grpc"
)

var (
	// 全局中间件
	fgrpcUnaryMiddles = []FgrpcUnaryFunc{}
)

// Deprecated: grpc原生已实现。
//
// 声明中间件方法
type FgrpcUnaryFunc func(*FgrpcUnaryMiddItem)

// 增加中间件进入全局
func FgrpcUnaryMiddUse(handle ...FgrpcUnaryFunc) {
	fgrpcUnaryMiddles = append(fgrpcUnaryMiddles, handle...)
}

// grpc 一元请求 中间件
type FgrpcUnaryMiddItem struct {
	Ctx     context.Context
	Req     any                   // 请求参数
	Info    *grpc.UnaryServerInfo // 服务的一些信息
	handler grpc.UnaryHandler     // 执行一元方法
	index   int                   // 中间件执行顺序标识
	Out     any                   // 执行grpc方法后的结果
	OutErr  error                 // 执行grpc方法后的err
	isEnd   bool                  // 是否执行完最后一个中间件, 或者已执行 Abort
	isAbort bool                  // 是否执行了Abort
}

// 执行下一步
func (f *FgrpcUnaryMiddItem) Next() {
	if f.isEnd {
		return
	}
	f.index += 1
	if f.index >= len(fgrpcUnaryMiddles) {
		f.isEnd = true
		m, err := f.handler(f.Ctx, f.Req)
		f.Out = m
		f.OutErr = err
		return
	}
	// 递归往下执行
	fgrpcUnaryMiddles[f.index](f)
}

// 停止执行
func (f *FgrpcUnaryMiddItem) Abort(err error) {
	f.isEnd, f.isAbort = true, true
	f.Out = nil
	f.OutErr = err
}

func (f *FgrpcUnaryMiddItem) IsEnd() bool {
	return f.isEnd
}

func (f *FgrpcUnaryMiddItem) IsAbort() bool {
	return f.isAbort
}

// Deprecated: grpc原生已实现。
//
//	获取一元拦截器
func FgrpcUnaryInterceptor() grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
		unaryMiddItem := &FgrpcUnaryMiddItem{
			Ctx:     ctx,
			Req:     req,
			Info:    info,
			handler: handler,
			index:   0,
		}
		fgrpcUnaryMiddles[0](unaryMiddItem)
		m, err := unaryMiddItem.Out, unaryMiddItem.OutErr
		return m, err
	}
}
